﻿using System;
using System.Collections.Generic;
using System.Diagnostics.Contracts;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;

namespace Sundstrom.Validation
{
    public static class Validator
    {
        public static bool TryValidateObject(object objectInstance, ICollection<ValidationResult> results)
        {
            Contract.Requires(objectInstance != null);
            Contract.Requires(results != null);

            bool result = true;
#if NET45
            var type = objectInstance.GetType();
            foreach(var propertyInfo in type.GetRuntimeProperties())
            {
                result = result && validateProperty(objectInstance, propertyInfo, results);
            }
#endif
#if NET4          
            var type = objectInstance.GetType();
            foreach (var propertyInfo in type.GetProperties())
            {
                result = result && validateProperty(objectInstance, propertyInfo, results);
            }
#endif
            return result;
        }

        public static bool TryValidateProperty(object objectInstance, string propertyName, ICollection<ValidationResult> results)
        {
            Contract.Requires(objectInstance != null);
            Contract.Requires(!string.IsNullOrEmpty(propertyName));
            Contract.Requires(results != null);

            PropertyInfo propertyInfo = null;
            var type = objectInstance.GetType();
#if NET45          
            propertyInfo = type
                .GetRuntimeProperties()
                .First(x => x.Name == propertyName);
#endif
#if NET4
            propertyInfo = type
                .GetProperties()
                .First(x => x.Name == propertyName);
#endif
            return validateProperty(objectInstance, propertyInfo, results);
        }

        private static bool validateProperty(object objectInstance, PropertyInfo propertyInfo, ICollection<ValidationResult> results)
        {
            bool result = true;
            var attributes = propertyInfo.GetCustomAttributes(typeof(ValidationAttribute), true)
                .Cast<ValidationAttribute>();
            var value = propertyInfo.GetValue(objectInstance, null);
            foreach (var attribute in attributes)
            {
                var validationResult = attribute.Validate(value, 
                    new ValidationContext(objectInstance, propertyInfo.Name, attribute.ErrorMessage));
                if (validationResult != null)
                {
                    results.Add(validationResult);
                }
                result = result && (validationResult == null);
            }
            return result;
        }
    }
}
